﻿Imports System.ServiceModel.Channels

<ServiceBehavior(ConcurrencyMode:=ConcurrencyMode.Multiple, InstanceContextMode:=InstanceContextMode.Single)> _
Public Class DisplayServer
    Implements IDisplayServer

    Public Displays As New Dictionary(Of Integer, Display)
    Dim LastStatus As New Dictionary(Of Integer, List(Of String))
    Dim LastStatusWithDetails As New Dictionary(Of Integer, String)
    Dim LastScores As New Dictionary(Of Integer, SortedList(Of String, Long))
    Dim LastQuestion As New Dictionary(Of Integer, Question)
    Dim LastCorrectAnswer As New Dictionary(Of Integer, String)
    Dim WithEvents GameServer As GameServer

    Dim DisplayChecker As Threading.Timer

    Public Sub New(ByVal GameServer As GameServer)
        Me.GameServer = GameServer
        DisplayChecker = New Threading.Timer(New Threading.TimerCallback(AddressOf DisplayCheck), Nothing, 5000, 5000)
    End Sub

    Public Sub New()

    End Sub

    Sub DisplayCheck()
        For Each Display As KeyValuePair(Of Integer, Display) In Displays.ToArray
            If Not Display.Value.LastSeen.AddSeconds(15) >= Now Then
                Goodbye(Display.Key)
            End If
        Next
    End Sub

    Public Function Hello() As Integer Implements IDisplayServer.Hello
rand:   Dim Index As Integer = (New Random).Next(10, 100) * (New Random).Next(10, 100)
        If Displays.ContainsKey(Index) Then GoTo rand
        Displays.Add(Index, New Display With {.RequiredUpdates = New List(Of RequiredUpdate), .GameInteger = -1, .LastSeen = Now})
        LastQuestion.Add(Index, Nothing)
        LastScores.Add(Index, Nothing)
        LastStatus.Add(Index, New List(Of String))
        LastCorrectAnswer.Add(Index, Nothing)
        Displays(Index).RequiredUpdates.Add(RequiredUpdate.CurrentGames)
        Try
            With GameServer.ServerData.Usage_Data
                .AddUsage_DataRow(Now, .Last.MainClientCount, Displays.Count)
            End With
        Catch
        End Try
        Return Index
    End Function

    Public Function NeedUpdate(ByVal DisplayID As Integer) As RequiredUpdate Implements IDisplayServer.NeedUpdate
        Try
            Displays(DisplayID).LastSeen = Now
            Dim RequiredUpdates As List(Of RequiredUpdate) = Displays(DisplayID).RequiredUpdates
            If RequiredUpdates.Count = 0 Then
                Return RequiredUpdate.None
            Else
                Dim RequiredUpdate As RequiredUpdate = RequiredUpdates(0)
                RequiredUpdates.RemoveAt(0)
                Return RequiredUpdate
            End If
        Catch
            Return RequiredUpdate.None
        End Try
    End Function

    Public Sub MainPage(ByVal DisplayID As Integer) Implements IDisplayServer.MainPage
        Displays(DisplayID).LastSeen = Now
        Displays(DisplayID).GameInteger = -1
        Displays(DisplayID).RequiredUpdates.Add(RequiredUpdate.CurrentGames)
    End Sub

    Public Function GetGames(ByVal DisplayID As Integer) As Dictionary(Of String, Integer) Implements IDisplayServer.GetGames
        Displays(DisplayID).LastSeen = Now
        Return GameServer.GameNames
    End Function

    Public Function GetStatus(ByVal DisplayID As Integer) As String Implements IDisplayServer.GetStatus
        Displays(DisplayID).LastSeen = Now
        Dim Status As String = LastStatus(DisplayID)(0)
        LastStatus(DisplayID).RemoveAt(0)
        Return Status
    End Function

    Public Sub GamePage(ByVal DisplayID As Integer, ByVal GameName As String) Implements IDisplayServer.GamePage
        Displays(DisplayID).LastSeen = Now
        Displays(DisplayID).GameInteger = GameServer.GameNames(GameName)
        Displays(DisplayID).RequiredUpdates.Add(RequiredUpdate.Scores)
    End Sub

    Public Function GetScores(ByVal DisplayID As Integer) As SortedList(Of String, Long) Implements IDisplayServer.GetScores
        Displays(DisplayID).LastSeen = Now
        Return LastScores(DisplayID)
    End Function

    Public Function GetQuestion(ByVal DisplayID As Integer) As Question Implements IDisplayServer.GetQuestion
        Displays(DisplayID).LastSeen = Now
        Return LastQuestion(DisplayID)
    End Function

    Public Function GetCorrectAnswer(ByVal DisplayID As Integer) As String Implements IDisplayServer.GetCorrectAnswer
        Displays(DisplayID).LastSeen = Now
        Return (LastCorrectAnswer(DisplayID))
    End Function

    Public Sub Goodbye(ByVal DisplayID As Integer)
        LastQuestion.Remove(DisplayID)
        LastScores.Remove(DisplayID)
        LastStatus.Remove(DisplayID)
        LastCorrectAnswer.Remove(DisplayID)
        Displays.Remove(DisplayID)
        Try
            With GameServer.ServerData.Usage_Data
                .AddUsage_DataRow(Now, .Last.MainClientCount, Displays.Count)
            End With
        Catch
        End Try
    End Sub

    Private Sub GameServer_EndGame(ByVal ID As Integer) Handles GameServer.EndGame
        RemoveHandler GameServer.Games(ID).SendQuestion, AddressOf SendQuestion
        RemoveHandler GameServer.Games(ID).Start, AddressOf StartQuestion
        RemoveHandler GameServer.Games(ID).EndQuestion, AddressOf EndQuestion

        GameServer_UpdateServerStatus("Removed Game: " & GameServer.Games(ID).Name, "")

        For Each Display As Display In Displays.Values
            If Display.GameInteger = ID Then
                Display.GameInteger = -1
                Display.RequiredUpdates.Add(RequiredUpdate.EndGame)
            End If
            Display.RequiredUpdates.Add(RequiredUpdate.CurrentGames)
        Next
    End Sub

    Private Sub GameServer_NewGame(ByVal ID As Integer, ByVal Name As String) Handles GameServer.NewGame
        AddHandler GameServer.Games(ID).SendQuestion, AddressOf SendQuestion
        AddHandler GameServer.Games(ID).Start, AddressOf StartQuestion
        AddHandler GameServer.Games(ID).EndQuestion, AddressOf EndQuestion

        GameServer_UpdateServerStatus("Added Game: " & Name, "")

        For Each Display As Display In Displays.Values
            Display.RequiredUpdates.Add(RequiredUpdate.CurrentGames)
        Next
    End Sub

    Private Sub GameServer_UpdateGameScores(ByVal ID As Integer, ByVal Scores As System.Collections.Generic.SortedList(Of String, Long)) Handles GameServer.UpdateGameScores
        For Each Display As KeyValuePair(Of Integer, Display) In Displays
            If Display.Value.GameInteger = ID Then
                LastScores(Display.Key) = Scores
                Display.Value.RequiredUpdates.Add(RequiredUpdate.Scores)
            End If
        Next
    End Sub

    Private Sub GameServer_UpdateGameStatus(ByVal ID As Integer, ByVal Status As String, ByVal Detail As String) Handles GameServer.UpdateGameStatus
        For Each Display As KeyValuePair(Of Integer, Display) In Displays
            If Display.Value.GameInteger = ID Then
                If Detail = "" Then
                    LastStatus(Display.Key).Add(Status)
                    Display.Value.RequiredUpdates.Add(RequiredUpdate.Status)
                Else
                    If Not LastStatusWithDetails(ID) = Status Then
                        LastStatusWithDetails(ID) = Status
                        LastStatus(Display.Key).Add(Status)
                        Display.Value.RequiredUpdates.Add(RequiredUpdate.Status)
                    End If
                End If
            End If
        Next
    End Sub

    Private Sub GameServer_UpdateServerStatus(ByVal Status As String, ByVal Detail As String) Handles GameServer.UpdateServerStatus
        For Each Display As KeyValuePair(Of Integer, Display) In Displays
            If Display.Value.GameInteger = -1 Then
                LastStatus(Display.Key).Add(Status)
                Display.Value.RequiredUpdates.Add(RequiredUpdate.Status)
            End If
        Next
    End Sub

    Private Sub SendQuestion(ByVal GameID As Integer, ByVal Question As Question)
        For Each Display As KeyValuePair(Of Integer, Display) In Displays
            If Display.Value.GameInteger = GameID Then
                LastQuestion(Display.Key) = Question
                Display.Value.RequiredUpdates.Add(RequiredUpdate.SendQuestion)
            End If
        Next
    End Sub

    Private Sub StartQuestion(ByVal GameID As Integer)
        For Each Display As Display In Displays.Values
            If Display.GameInteger = GameID Then
                Display.RequiredUpdates.Add(RequiredUpdate.StartQuestion)
            End If
        Next
    End Sub

    Private Sub EndQuestion(ByVal GameID As Integer, ByVal CorrectAnswer As String, ByVal Explanation As String)
        For Each Display As KeyValuePair(Of Integer, Display) In Displays
            If Display.Value.GameInteger = GameID Then
                Display.Value.RequiredUpdates.Add(RequiredUpdate.EndQuestion)
                LastCorrectAnswer(Display.Key) = CorrectAnswer
            End If
        Next
    End Sub
End Class
